home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-04-27 | 5.7 KB | 182 lines | [TEXT/????] |
- ;;; $Header: ratfun.scm,v 1.6 88/09/21 13:38:15 GMT hal Exp $
- ;;;; 6.003 Rational Functions
-
- (if-mit
- (declare (usual-integrations = + - * /
- zero? 1+ -1+
- ;; truncate round floor ceiling
- sqrt exp log sin cos)))
-
- ;;; This file contains these definitions:
- ;;;
- ;;; (procedure->rat-func <procedure> <degree>) -> ( numer denom )
- ;;;
- ;;; (rat-func->procedure <ratfunc> [procedure])
- ;;;
- ;;; (rat-func-compose <rf1> <rf2>)
-
- ;;; The following procedure, given a function of complex frequency
- ;;; derived from a circuit of known degree, returns a list of lists of
- ;;; numbers that are the coefficients of the numerator and denominator
- ;;; polynomials. The list of lists ((a0 a1 a2) (b0 b1 b2 b3))
- ;;; corresponds to the rational function
- ;;;
- ;;; a2*s^2 + a1*s + a0
- ;;; --------------------------
- ;;; b3s^3 + b2*s^2 + b1*s + b0
- ;;;
- ;;; The degree supplied, n, corresponds to the max degree of the
- ;;; denominator or (which is the same thing) to 1 + the max degree of
- ;;; the numerator. If n is too small, the procedure will return the
- ;;; rational function that agrees with the values of the given
- ;;; procedure at 2n test points generated by TEST-POINTS. If n is too
- ;;; large, an error is signalled, indicating that the equations are
- ;;; not independent.
- ;;; The answer is normalized so that the highest non-zero power of s
- ;;; in the denominator has coefficient 1.
-
- (define (procedure->rat-func procedure n)
- (if (< n 1) (error "Bad maximum degree -- PROCEDURE->RAT-FUNC" n))
- (let* ((coeffs (rat-fun-vector procedure n))
- (a-part
- (generate-list n
- (lambda (i)
- (heuristic-round-complex (vector-ref coeffs i)))))
- (b-part
- (generate-list n
- (lambda (i)
- (heuristic-round-complex (vector-ref coeffs (+ i n)))))))
- (list (reverse (truncate-leading-zeros (reverse a-part)))
- (append b-part '(1))))) ;b[n]=1
-
-
- ;;; Inverse of `procedure->rat-func' is easy:
-
- (define (rat-func->procedure r . optional)
- (let ((r (check-rat-func r)))
- (let ((point (if (null? optional) identity-operator (car optional)))
- (numerator (car r))
- (denominator (cadr r)))
- (/ (poly-value numerator point) (poly-value denominator point)))))
-
- ;;; Below this point we implement the PROCEDURE->RAT-FUNC procedure.
-
-
- (define (truncate-leading-zeros l)
- (cond ((null? l) (list 0))
- ((= (car l) 0) (truncate-leading-zeros (cdr l)))
- (else l)))
-
-
- ;;; We generate the 2n by 2n matrix M of coefficients of the a[i]
- ;;; and b[i] obtained by evaluating f at 2n points and setting
- ;;; this equal to the desired rational form.
-
- (define (rat-fun-vector f n)
- (let ((e (assemble-matrix-equation f n)))
- (let ((A (car e)) (B (cadr e))) ;AX=B
- (let* ((lud (lu-decompose A allow-zero-pivot))
- (rank (lu-rank (car lud))))
- (if (= rank (* 2 n)) ;ok!
- (lu-backsubstitute (car lud) (cadr lud) B)
- (error "N is too large -- PROCEDURE->RAT-FUNC" n))))))
-
-
- ;;; This assembles the matrix of coefficients and the drive vector.
- ;;; The unknowns are in the order a[0], ... a[n-1], b[0], ... b[n-1].
- ;;; The rows are produced by evaluating f at 2n+1 test points.
-
- (define (assemble-matrix-equation f n)
- (let ((equations (map (lambda (i) (eqn i f n)) (test-points (* n 2)))))
- (list (matrix-by-rows (map cadr equations))
- (list->vector (map car equations)))))
-
-
- ;;; Test points are generated along a line parallel to the imaginary axis
- ;;; and spaced out to fit within a range near the unit circle.
-
- (define (test-points num)
- (map (lambda (imag) (make-rectangular test-point-real imag))
- (let ((space (/ test-point-imag (- num 1))))
- (let loop ((n num))
- (cond ((= n 0) '())
- ((odd? n)
- (cons (* n space) (loop (- n 1))))
- (else
- (cons (* -1 n space) (loop (- n 1)))))))))
-
- ;;; The following magic numbers are arbitrary
-
- (define test-point-real (/ 1 10))
- (define test-point-imag 1)
-
- ;;; Returns a representation of an equation:
- ;;; x^n*f(x) =
- ;;; a[0] + ... + x^(n-1)a[n-1] - f(x)*b[0] - ... - x^(n-1)*f(x)*b[n-1]
- ;;; as
- ;;; ( x^n*f(x) ( 1 ... x^(n-1) -f(x) ... - x^(n-1)*f(x) ) )
-
- (define (eqn x f n)
- ((with-reasonable-object x
- (lambda (x)
- (values x (f x))))
- (lambda (x fx)
- (let lp ((i 0) (xp 1) (acoeffs '()) (bcoeffs '()))
- (if (= i n)
- (list (* fx xp) ;rhs
- (append (reverse acoeffs) ;lhs
- (reverse bcoeffs)))
- (lp (1+ i)
- (* xp x)
- (cons xp acoeffs)
- (cons (* -1 xp fx) bcoeffs)))))))
-
- (define ((values . list) receiver)
- (apply receiver list))
-
-
- (define (rat-func-compose rf1 rf2)
- (let ((rf1 (check-rat-func rf1))
- (rf2 (check-rat-func rf2)))
- (let ((rf1 (pad-rat-func rf1))
- (rf2 (pad-rat-func rf2)))
- (define (make-list-poly-powers poly)
- (let loop ((power '(1))
- (index 1))
- (if (= index (length (car rf1)))
- (list power)
- (cons power
- (loop (mul-polys power poly) (1+ index))))))
- (let ((numer-power-list (make-list-poly-powers (car rf2)))
- (denom-power-list (make-list-poly-powers (cadr rf2))))
- (define (compose-poly&rat-func poly)
- (apply add-polys
- (map mul-polys
- (reverse (map scale-poly poly numer-power-list))
- denom-power-list)))
- (list (compose-poly&rat-func (car rf1))
- (compose-poly&rat-func (cadr rf1)))))))
-
-
- (define (pad-rat-func rf)
- (define (pad-coeff-list coeffs full-length)
- (let loop ((c (reverse coeffs))
- (extra (- full-length (length coeffs))))
- (if (= extra 0)
- (reverse c)
- (loop (cons 0 c)
- (-1+ extra)))))
- (let ((m (max (length (car rf))
- (length (cadr rf)))))
- (map (lambda (coeffs) (pad-coeff-list coeffs m))
- rf)))
-
-
- (define (check-rat-func r)
- (if (and (pair? r)
- (pair? (car r))
- (pair? (cdr r))
- (pair? (cadr r)))
- r
- (error "badly formed rational function --" r)))
-